package com.jeesite.modules.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jeesite.modules.common.Result;
import com.jeesite.modules.entity.LoginUser;
import com.jeesite.modules.utils.JwtUtils;
import com.jeesite.modules.utils.RedisUtils;
import com.jeesite.modules.utils.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * JWT Token验证拦截器
 * 第二个拦截器，负责Token验证和权限控制
 */
@Component
@Order(2)
public class JwtTokenInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(JwtTokenInterceptor.class);

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtils redisUtils;

    // 不需要验证Token的路径
    private static final List<String> EXCLUDE_PATHS = Arrays.asList(
        "/api/auth/login",
        "/api/auth/register",
        "/api/auth/server-status",
        "/error",
        "/favicon.ico",
            "/a/**"
    );

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String originalURI = request.getRequestURI();
        String contextPath = request.getContextPath();
        String requestURI = originalURI;

        // 添加详细的调试日志
        System.out.println("=== JWT拦截器被调用 ===");
        System.out.println("JWT拦截器 - 原始URI: " + originalURI + ", 上下文路径: " + contextPath);
        logger.info("JWT拦截器 - 原始URI: {}, 上下文路径: {}", originalURI, contextPath);

        // 移除上下文路径
        if (StringUtils.hasText(contextPath)) {
            requestURI = requestURI.substring(contextPath.length());
        }

        logger.info("JWT拦截器 - 处理后URI: {}", requestURI);

        // 检查是否是排除路径
        boolean isExcluded = isExcludePath(requestURI);
        logger.info("JWT拦截器 - 路径 {} 是否被排除: {}", requestURI, isExcluded);

        if (isExcluded) {
            logger.info("JWT拦截器 - 路径 {} 在排除列表中，直接放行", requestURI);
            return true;
        }

        // OPTIONS请求直接放行
        if ("OPTIONS".equals(request.getMethod())) {
            return true;
        }

        try {
            // 获取Token
            String token = getTokenFromRequest(request);
            if (!StringUtils.hasText(token)) {
                writeErrorResponse(response, Result.unauthorized("Token不能为空"));
                return false;
            }

            // 验证Token
            if (!jwtUtils.validateToken(token)) {
                writeErrorResponse(response, Result.unauthorized("Token无效或已过期"));
                return false;
            }

            // 获取用户信息
            String username = jwtUtils.getUsernameFromToken(token);
            if (!StringUtils.hasText(username)) {
                writeErrorResponse(response, Result.unauthorized("Token中用户信息无效"));
                return false;
            }

            // 检查Redis中的Token（确保只有最新Token有效，防止多平台登录）
            String cachedToken = redisUtils.getToken(username);
            if (!token.equals(cachedToken)) {
                writeErrorResponse(response, Result.unauthorized("Token已失效，请重新登录"));
                return false;
            }

            // 获取用户ID并创建LoginUser对象
            Long userId = jwtUtils.getUserIdFromToken(token);
            LoginUser loginUser = new LoginUser(userId, username);

            // 将用户信息存储到ThreadLocal中
            UserContext.setCurrentUser(loginUser);

            // 同时存储到请求属性中（兼容性）
            request.setAttribute("username", username);
            request.setAttribute("userId", userId);

            logger.debug("Token验证成功: {}", username);
            return true;

        } catch (Exception e) {
            logger.error("Token验证异常: {}", e.getMessage(), e);
            writeErrorResponse(response, Result.unauthorized("Token验证失败"));
            return false;
        }
    }

    /**
     * 检查是否是排除路径
     */
    private boolean isExcludePath(String requestURI) {
        logger.info("JWT拦截器 - 检查排除路径，当前URI: {}", requestURI);
        logger.info("JWT拦截器 - 排除路径列表: {}", EXCLUDE_PATHS);

        for (String excludePath : EXCLUDE_PATHS) {
            boolean matches = requestURI.startsWith(excludePath);
            logger.info("JWT拦截器 - 检查路径 '{}' 是否以 '{}' 开头: {}", requestURI, excludePath, matches);
            if (matches) {
                return true;
            }
        }
        return false;
    }

    /**
     * 从请求中获取Token
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        return request.getHeader("access-key");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求完成后清除ThreadLocal中的用户信息，防止内存泄漏
        UserContext.clear();
    }

    /**
     * 写入错误响应
     */
    private void writeErrorResponse(HttpServletResponse response, Result<?> result) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");

        String origin = response.getHeader("Origin");
        if (StringUtils.hasText(origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
        } else {
            response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); // 根据实际情况修改
        }
//        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");

        ObjectMapper objectMapper = new ObjectMapper();
        String jsonResult = objectMapper.writeValueAsString(result);
        response.getWriter().write(jsonResult);
    }
}
